關於 React 小書:做出 React


Posted by YongChenSu on 2020-12-09

做出 React 的程式碼

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3. practive</title>
  <style media="screen">
    .like-btn { font-size: 50px; }
  </style>
</head>
<body>
  <div class='wrapper'></div>
  <script type="text/javascript">
    const createDOMFromString = (domString) => {
      const div = document.createElement('div')
      div.innerHTML = domString
      return div
    }

    class Component {
      constructor (props = {}) {
        this.props = props
      }

      // 改變狀態
      setState (state) {
        // 將舊 (dom element) 儲存為變數
        const oldEl = this.el
        // 更新 state
        this.state = state
        // 更新 dom element
        this.el = this.renderDOM()
        // 觸發 onstateChange 函式
        if (this.onStateChange) this.onStateChange(oldEl, this.el)
      }

      // 渲染畫面
      renderDOM () {
        // 將 string 變成 dom element
        this.el = createDOMFromString(this.render())
        // 若觸發 onClick 函式
        if (this.onClick) {
          // dom element 上觸發 click 事件,
          this.el.addEventListener('click', this.onClick.bind(this), false)
        }
        // 回傳觸發 click 事件後的 dom element
        return this.el
      }
    }

    // 將 dom element 用 mount 函式加到 container 上
    const mount = (component, wrapper) => {
      // 將渲染後且有觸發 click 事件的 dom 元素放到 wrapper 中
      wrapper.appendChild(component.renderDOM())
      // 在傳入的 component 加上 onStateChange 函式,依序傳入新舊兩個 dom element
      component.onStateChange = (oldEl, newEl) => {
        // 將新的 element 插在舊的 element 之前
        wrapper.insertBefore(newEl, oldEl)
        // 移除舊的 element
        wrapper.removeChild(oldEl)
      }
    }

    // 建立 LikeButton 類並繼承 Component
    class LikeButton extends Component {
      // 初始化並傳入 props
      constructor (props) {
        // 呼叫父類並將 props 傳上去
        super(props)
        // 初始化 this.state.isLiked 是 false
        this.state = { isLiked: false}
      }

      // onClick 函式
      onClick () {
        // 若觸發 onClick 函式則重新設置狀態
        this.setState({
          // 將 this.state.isLiked 的值設為相反
          isLiked: !this.state.isLiked
        })
      }

      // 渲染,回傳 string
      render() {
        return `
          <button class='like-btn' style="background-color: ${this.props.bgColor}">
            <span class='like-text'>
              ${this.state.isLiked ? '取消' : '點讚'}
            </span>
            <span>👍</span>
          </button>
        `
      }
    }

    // 選到帶有 wrapper css 屬性的 dom 元素
    const wrapper = document.querySelector('.wrapper')
    /* 
      建立新的 instance:LikeButton、傳入 props
      並利用 mount 函式將其放在 wrapper 中
    */
    mount(new LikeButton({ bgColor: 'red' }), wrapper)
    mount(new LikeButton(), wrapper)

  </script>
</body>
</html>


參考資源


#程式導師實驗計畫第四期 #前端 #React







Related Posts

Elevate Your Dermatology Practice with the Electric Dermatology Chair

Elevate Your Dermatology Practice with the Electric Dermatology Chair

邏輯論證(Logical Argument)

邏輯論證(Logical Argument)

React 部署上 Github pages

React 部署上 Github pages


Comments